package net.flowas.modulecaert.testsupport;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;

public class RemoteInvokeHandler implements InvocationHandler{
	private WebTarget webTarget ;
	private static String baseUrl;
	private static Stack<Class<?>> currentInterface=new Stack<>();
	public static void push(Class<?> clasz){
		currentInterface.push(clasz);
	}
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		String pathText="";
		//Path classPath = method.getDeclaringClass().getAnnotation(Path.class);
		Class<?> interfaceClass = currentInterface.pop();
		ParameterizedType ints = (ParameterizedType) interfaceClass.getGenericInterfaces()[0];
		Class type = (Class) ints.getActualTypeArguments()[0];
		Path classPath =interfaceClass.getAnnotation(Path.class);
		if(classPath!=null){
			pathText=classPath.value();
		}
		Path path = method.getAnnotation(Path.class);		
		if(path!=null){
			pathText = pathText+path.value();
		}
		Object postEntity=null;
		Map<String,Object> queryParams=new HashMap<>();
		Annotation[][] parameterAnnotations = method.getParameterAnnotations();
	    for (int i = 0; i < parameterAnnotations.length; i++) {
			Annotation annotation = filterRestParamType(parameterAnnotations[i]);
			if(annotation instanceof PathParam){
				pathText = pathText.replace("{"+((PathParam)annotation).value()+"}", ""+args[i]);
			}else if(annotation instanceof QueryParam){
				queryParams.put(((QueryParam)annotation).value(), args[i]);
			}else{
				postEntity=args[i];
			}
		}
		WebTarget currentTarget = webTarget.path(pathText);
		for(String queryParam:queryParams.keySet()){
			currentTarget=currentTarget.queryParam(queryParam, queryParams.get(queryParam));
		}
		Builder builder = currentTarget.request();
		Response response;
		if(method.getAnnotation(GET.class)!=null){
			response=builder.buildGet().invoke();
		}else if(method.getAnnotation(POST.class)!=null){
			response=builder.buildPost(Entity.entity(postEntity, MediaType.APPLICATION_JSON)).invoke();
		}else if(method.getAnnotation(PUT.class)!=null){
			response=builder.buildPut(Entity.entity(postEntity, MediaType.APPLICATION_JSON)).invoke();
		}else if(method.getAnnotation(DELETE.class)!=null){
			response=builder.buildDelete().invoke();
		}else{
			throw new RuntimeException("请求方法不正确！");
		}
		Object result = response.readEntity(type==null?method.getReturnType():type);
		return result;
	}
    public RemoteInvokeHandler() {
    	Client client = ClientBuilder.newClient();
    	webTarget = client.register(JacksonJsonProvider.class).target( getBaseUri());
	}
    private String getBaseUri() {
    	if(baseUrl!=null){
    		return baseUrl;
    	}else{
    		return "http://localhost:8181/rest/shop/";
    	}
    }
    public static void setBaseUrl(String baseUrl2) {    	
    	baseUrl = baseUrl2;
	}
	private Annotation filterRestParamType(Annotation[] annotations){
    	for (Annotation annotation : annotations) {
			if(annotation instanceof PathParam || annotation instanceof QueryParam){
				return annotation;
			}
		}
    	return null;
    }
}
